#pragma once

#include "protocol.hpp"
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <functional>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

typedef function<void(httpRequest&, httpResponse*)> func_t;

enum
{
    USAGE_ERR = 0,
    SOCK_ERR,
    BIND_ERR,
    LISTEN_ERR,
    ACCEPT_ERR,
};

const int gbacklog = 5;

struct ThreadData
{
    int sockfd;
    func_t func;
};

void serverIO(ThreadData* td)
{
    //读取客户端发送的请求报文
    //对报文进行解析及反序列化处理
    //根据结构化的请求数据进行业务逻辑处理 得到请求的处理结果
    //对处理结果进行序列化
    //将处理结果包装为报文发送给客户端
    char buffer[4096];
    httpRequest req;
    int n = recv(td->sockfd, buffer, sizeof buffer - 1, 0);
    if (n > 0)
    {
        buffer[n] = 0;
        req.inbuffer = buffer;
        req.parse();
        httpResponse res;
        td->func(req, &res);
        send(td->sockfd, res.outbuffer.c_str(), res.outbuffer.size(), 0);
    }
}

class httpServer
{
public:
    httpServer(int16_t port)
    : _port(port)
    {}

    void initServer()
    {
        //创建socket
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensock == -1)
        {
            cerr << "create listensock error" << endl;
            exit(SOCK_ERR);
        }
        cout << "create listensock success" << endl;
        //绑定ip port
        struct sockaddr_in server;
        memset(&server, 0, sizeof server);
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = INADDR_ANY;//绑定任意ip 通过多类ip都可以向服务器发送消息
        server.sin_port = ntohs(_port);
        if (bind(_listensock, (struct sockaddr*)&server, sizeof server) == -1)
        {
            cout << "bind error" << endl;
            exit(BIND_ERR);
        }
        cout << "bind success" << endl;
        //设置监听
        if (listen(_listensock, gbacklog) == -1)
        {
            cout << "set listen error" << endl;
            exit(LISTEN_ERR);
        }
        cout << "set listen success" << endl;
    }

    void startServer(func_t func)
    {
        struct sockaddr_in client;
        socklen_t len;
        // 接收新链接
        while (true)
        {
            memset(&client, 0, sizeof client);
            int sockfd = accept(_listensock, (struct sockaddr *)&client, &len);
            if (sockfd == -1)
            {
                cout << "accept link error" << endl;
                exit(ACCEPT_ERR);
            }

            //创建线程处理客户端的请求 主线程继续接收其他客户端的链接
            ThreadData* td = new ThreadData;
            td->sockfd = sockfd;
            td->func = func;
            pthread_t tid;
            pthread_create(&tid, nullptr, start_routine, td);
        }
    }

private:
    static void* start_routine(void* args)
    {
        pthread_detach(pthread_self());//断开与主线程的联系 主线程无需等待从线程退出
        ThreadData* td = (ThreadData*)args;
        serverIO(td);
        close(td->sockfd);//处理完客户端的请求后 需要释放与客户端进行通信的fd
        delete td;
        return nullptr;
    }

private:
    int _listensock;
    int16_t _port;
};